package com.eclink.iot.base;

import com.eclink.iot.rfid.RFIDDeviceClient;
import com.eclink.iot.rfid.RFIDServer;
import com.eclink.iot.utils.ByteUtils;
import com.eclink.iot.utils.Log;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

@Slf4j
public abstract class SocketClientBase extends Thread {

  protected String TAG = "";

  @Getter
  private final Socket socket;

  private InputStream input_stream;

  private DataInputStream data_input_stream;

  private OutputStream output_stream;

  protected String uuid;

  protected String version;

  protected int runtime = 0;
  
  protected boolean is_running = true;
  
  protected abstract void concat_data(byte[] paramArrayOfByte, int paramInt);
  
  public SocketClientBase(Socket socket) {
    this.socket = socket;
  }
  
  public void release() {
    this.is_running = false;

    try {
      if (this.data_input_stream != null) {
        this.data_input_stream.close();
      }
      if (this.input_stream != null) {
        this.input_stream.close();
      }
      if (this.output_stream != null) {
        this.output_stream.close();
      }
      if (this.socket != null) {
        this.socket.close();
      }
    } catch (Exception e) {
      log.error("release client error", e);
    }
    RFIDServer.releaseDeviceClient((RFIDDeviceClient) this);
  }
  
  protected boolean write(byte... buffer) {
    try {
      this.output_stream = this.socket.getOutputStream();
      this.output_stream.write(buffer);
      return true;
    } catch (Exception e) {
      log.error("write error", e);
      release();
      
      return false;
    } 
  }
  
  protected boolean write(byte[] buffer, int length) {
    boolean result = false;
    try {
      result = write(ByteUtils.subString(buffer, 0, length));
    } catch(Exception ex) {
      log.error("write error {}", ex.getMessage());
    }
    return result;
  }
  
  public void run() {
    try {
      this.input_stream = this.socket.getInputStream();
      
      this.data_input_stream = new DataInputStream(this.input_stream);
      
      while (this.is_running) {
        
        try {
          if (this.data_input_stream.available() > 0) {
            
            byte[] buffer = new byte[1024];
            int length = this.data_input_stream.read(buffer);
            
            if (length == -1) {
              Log.e(this.TAG, "client disconnected");
              
              break;
            }

            concat_data(buffer, length);
          } 

        } catch (Exception e) {
          log.error("read bytes error", e);
        } 
      }
    } catch (Exception e) {
      log.error("socket reading error", e);
    } 
  }

}
